package com.bwie.es.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bwie.common.domain.request.GoodsQueryReq;
import com.bwie.common.domain.response.GoodsQueryRes;
import com.bwie.common.result.PageResult;
import com.bwie.common.result.Result;
import com.bwie.common.utils.StringUtils;
import com.bwie.es.service.GoodsEsService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class GoodsEsServiceImpl implements GoodsEsService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;
    private static final String INDEX_NAME="goods";

    @Override
    public Result<PageResult<GoodsQueryRes>> search(GoodsQueryReq goodsQueryReq) {
        long total = 0;
        ArrayList<GoodsQueryRes> goodsQueryRes = new ArrayList<>();
        try {
            //创建 查询请求对象
            SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
            //创建 条件查询构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //多条件拼接
            //创建 多条件拼接对象
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if (StringUtils.isNotBlank(goodsQueryReq.getGoodsName())){
                boolQueryBuilder.must(QueryBuilders.matchQuery("goodsName",goodsQueryReq.getGoodsName()));
            }
            if (goodsQueryReq.getTypeId()!=null){
                boolQueryBuilder.must(QueryBuilders.matchQuery("typeId",goodsQueryReq.getTypeId()));
            }
            if (goodsQueryReq.getStartTime()!=null){
                boolQueryBuilder.must(QueryBuilders .rangeQuery("goodsTime").gte(goodsQueryReq.getStartTime().getTime()));
            }
            if (goodsQueryReq.getEndTime()!=null){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("goodsTime").lte(goodsQueryReq.getEndTime().getTime()));
            }
            //把 条件拼接对象 给 条件查询构造器
            searchSourceBuilder.query(boolQueryBuilder);
            //分页
            searchSourceBuilder.from((goodsQueryReq.getPageSize()-1)*goodsQueryReq.getPageSize());
            searchSourceBuilder.size(goodsQueryReq.getPageSize());
            //排序
            searchSourceBuilder.sort("goodsTime", SortOrder.DESC);
            //高亮
            searchSourceBuilder.highlighter(new HighlightBuilder().field("goodsName").preTags("<span style=\"color:red\">").postTags("</span>"));
            //把 条件查询构造器 给 查询请求
            searchRequest.source(searchSourceBuilder);
            //发送请求 (得到一个大的对象)
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //获得里面的 hits
            SearchHits hits = searchResponse.getHits();
            //获取总记录数
            total = hits.getTotalHits().value;
            //取里面的 数据(获取当前页数据)
            SearchHit[] searchHits = hits.getHits();
            //循环遍历
            for (SearchHit searchHit : searchHits) {
                //得到 JSON字符串
                String sourceAsString = searchHit.getSourceAsString();
                //反序列化
                GoodsQueryRes queryRes = JSONObject.parseObject(sourceAsString, GoodsQueryRes.class);
                //获取所有高亮字段
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                if (highlightFields!=null){
                    //获取指定的高亮字段
                    HighlightField highlightField = highlightFields.get("goodsName");
                    if (highlightField!=null){
                        //获取碎片
                        Text[] fragments = highlightField.getFragments();
                        String str = "";
                        for (Text fragment : fragments) {
                            str+=fragment;
                        }
                        //替换
                        queryRes.setGoodsName(str);
                    }
                }
                queryRes.setGoodsId(Integer.valueOf(searchHit.getId()));
                goodsQueryRes.add(queryRes);
            }
        }catch (Exception e){
        }
        return PageResult.toResult(total,goodsQueryRes);
    }

    @Override
    public void batchAdd(List<GoodsQueryRes> goodsQueryRes) {
        try {
            //创建 批量请求对象
            BulkRequest bulkRequest = new BulkRequest();
            //遍历 商品信息
            goodsQueryRes.forEach(queryRes -> {
                bulkRequest.add(new IndexRequest(INDEX_NAME)
                        .id(queryRes.getGoodsId()+"")
                        .source(JSONObject.toJSONString(queryRes), XContentType.JSON));
            });
            restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteAll() {
        try {
            //创建 根据查询条件删除请求对象
            DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(INDEX_NAME);
            //设置 删除的条件
            deleteByQueryRequest.setQuery(QueryBuilders.matchAllQuery());
            //发送请求
            restHighLevelClient.deleteByQuery(deleteByQueryRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
